package org.ns.summer.core;

import net.sf.cglib.core.internal.Function;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class BeanUtils {

    public final static List<Method> getMethods(Class<?> beanType, Class<? extends  Annotation> annType) {
        List<Method> result = new ArrayList<>();
        Method[] methods = beanType.getDeclaredMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(annType)) {
                if (!method.isAccessible() ) {
                    method.setAccessible(true);
                }
                result.add(method);
            }
        }
        return result;
    }

    public final static Object invoke(Method method, Object object, Object... args) {
        if (method == null) {
            return null;
        }
        try {
            if (!method.isAccessible()) {
                method.setAccessible(true);
            }
            return method.invoke(object, args);
        } catch (Exception e) {
            throw new RuntimeException("方法执行异常:" + method.getName(), e);
        }
    }

    public static Class<?> createClass(String classname, ClassLoader classLoader) throws ClassNotFoundException {
        if (classname.isEmpty()) {
            return null;
        }
        return Class.forName(classname, false, classLoader);
    }

    public static boolean isSuperClass(String classname, ClassLoader classLoader, Class<?> superClass) throws ClassNotFoundException {
        Class<?> currentClass = createClass(classname, classLoader);
        return superClass.isAssignableFrom(currentClass);
    }


    public static List<Class<?>> getAllClass(Class<?> type, Function<Class<?>, Boolean> exclude) {
        List<Class<?>> types = new ArrayList<>();
        types.add(type);
        Set<Class<?>> sss = new HashSet<>();

        for (int i = 0; i < types.size(); i++) {
            Class<?> aClass = types.get(i);
            if (exclude != null && exclude.apply(aClass)) {
                continue;
            }


            Class<?> interfaces[] = aClass.getInterfaces();
            for (Class<?> anInterface : interfaces) {
                if (sss.add(anInterface)) {
                    types.add(anInterface);
                }
            }
            Class<?> superclass = aClass.getSuperclass();
            if (superclass != null && superclass != Object.class) {
                types.add(superclass);
            }
        }
        return types;
    }


    public static Object getDefaultValue(Class<?> beanType) {
        if (!beanType.isPrimitive()) {
            return null;
        }
        if (beanType == byte.class) {
            return (byte)0;
        }
        if (beanType == short.class) {
            return (short)0;
        }
        if (beanType == int.class) {
            return 0;
        }
        if (beanType == float.class) {
            return 0f;
        }
        if (beanType == long.class) {
            return 0L;
        }
        if (beanType == double.class) {
            return 0d;
        }
        if (beanType == boolean.class) {
            return false;
        }
        if (beanType == char.class) {
            return '\0';
        }
        return null;
    }
    public static Object getValue(String value, Class<?> beanType, TypeFunction other) throws Exception{
        if (beanType == null) {
            return getDefaultValue(beanType);
        }
        if (beanType == String.class) {
            return value;
        }
        if (value.isEmpty()) {
            return getDefaultValue(beanType);
        }
        if (beanType == byte.class || beanType == Byte.class) {
            return (byte)Integer.parseInt(value);
        }
        if (beanType == short.class || beanType == Short.class) {
            return (short)Integer.parseInt(value);
        }
        if (beanType == int.class || beanType == Integer.class) {
            return Integer.parseInt(value);
        }
        if (beanType == float.class || beanType == Float.class) {
            return Float.parseFloat(value);
        }
        if (beanType == long.class || beanType == Long.class) {
            return Long.parseLong(value);
        }
        if (beanType == double.class || beanType == Double.class) {
            return Double.parseDouble(value);
        }
        if (beanType == boolean.class || beanType == Boolean.class) {
            return value.equals("true");
        }
        if (beanType == char.class || beanType == Character.class) {
            return value.isEmpty() ? '\0' : value.charAt(0);
        }
        if (other == null) {
            return null;
        }
        return other.apply(beanType, value);
    }

    public static int setFieldValue(String name, Object bean, Object value) {
        try {
            Field declaredField = bean.getClass().getDeclaredField(name);
            declaredField.setAccessible(true);
            declaredField.set(bean, value);
            return 1;
        } catch (NoSuchFieldException e) {
            return -1;
        } catch (Exception e) {
            return 0;
        }
    }
    @FunctionalInterface
    public static interface TypeFunction {
        Object apply(Class<?> beanType, String value) throws Exception;
    }
}
